<?php
/**
 * This is the file to define BaseModule.
 * 
 * @author	Justin Yoo
 * @version	0.0.1.0001
 * @package	KYR.Core
 * 
 */

//	Checks if this file is called within the framework; otherwise terminates.
if (!defined("IS_FRAMEWORK") || !IS_FRAMEWORK)	header("Location: http://".$_SERVER["HTTP_HOST"]."/error/404");

/**
 * This is class BaseModule that defines basic properties and methods of each class inherited.
 *
 * Defines basic properties and methods of each class inherited.
 * 
 * @author	Justin Yoo
 * @package	KYR.Core
 * @abstract
 * 
 */
abstract class BaseModule extends BaseObject
{
	protected $variables_ = null;
	protected $templates_ = null;

	/**
	 * Initiates the BaseModule class.
	 *
	 * @access	public
	 * @param	Request	$request	Request object that contains page request details.
	 * @param	int		$statusCode	Page response code.
	 *
	 */
	public function __construct($request, $statusCode = 200)
	{
		parent::__construct();

		$this->request		= $request;
		$this->existModule	= false;
		$this->statusCode	= $statusCode;
		$this->moduleID		= null;
		$this->variables_	= array();
		$this->templates_	= array();
	}

	/**
	 * Checks if the module exists or not.
	 *
	 * @access	protected
	 * @exception	Throws an Exception while processing a database query.
	 *
	 */
	protected function CheckModule_()
	{
		$db				= null;
		if ($this->statusCode == 200)
		{
			try
			{
				$db = new Database("MySQL");
				$qry = "CALL cms_CheckModule(";
				$qry .= "'".$db->Quote($this->moduleName)."', ";
				$qry .= $this->request->pageID;
				$qry .= ")";
				$db->Query($qry);
				$row = $db->Fetch();

				if (isset($row) && count($row) > 0)
				{
					$this->existModule	= true;
					$this->statusCode	= 200;
					$this->moduleID		= $row["moduleID"];
				}
				else
				{
					$this->existModule	= false;
					//$this->statusCode	= 404;
				}
			}
			catch (Exeption $ex)
			{
				$this->statusCode	= 500;
				throw $ex;
			}
		}
	}
	
	/**
	 * Processes the module.
	 *
	 * @access	public
	 * @abstract
	 *
	 */
	abstract public function ProcessModule();

	/**
	 * Renders the templates corresponding to the module.
	 *
	 * @access	protected
	 * @abstract
	 *
	 */
	abstract protected function RenderTemplates_();
	
	/**
	 * Processe the module.
	 *
	 * @access	protected
	 * @exception	Throws an Exception while processing a database query.
	 *
	 */
	protected function ProcessModule_()
	{
		try
		{
			//	Loads components corresponding to the module.
			$components	= $this->_LoadComponents();
			//Debug::PrintScreen("pre", $components);

			//	Processes each component.
			if (isset($components) && count($components) > 0)
				foreach ($components as $component)
					$component->ProcessComponent($this->variables_);

			//	Loads templates corresponding to the module.
			$this->templates_ = $this->_LoadTemplates();
		}
		catch (Exception $ex) { throw $ex; }
	}

	/**
	 * Loads components corresponding to the module.
	 *
	 * @access	private
	 * @exception	Throws an Exception while processing a database query.
	 *
	 */
	private function _LoadComponents()
	{
		$components		= array();
		$componentNames	= array();
		try
		{
			//	Gets the list of component names based on the status code.
			if ($this->statusCode == 200)
				$componentNames	= $this->GetObjectNames_("component");
			else
				$componentNames[] = array("component" => "ContentView");
			//Debug::PrintScreen("pre", $componentNames);

			//	Gets the list of components.
			if (isset($componentNames) && count($componentNames) > 0)
			{
				foreach ($componentNames as $componentName)
				{
					$filename = COMPONENT_PATH."KYR.Components.".$componentName["component"].".php";

					if (file_exists($filename))
						require_once $filename;
					else
						throw new Exception("Component not found");

					$component = new $componentName["component"]($this->request, $this->moduleID, "module", $this->statusCode);
					$components[$componentName["component"]] = $component;
				}
			}
			else
				throw new Exception("Component not found");
		}
		catch (Exception $ex) { throw $ex; }
		return $components;
	}
	
	/**
	 * Loads templates corresponding to the module.
	 *
	 * @access	private
	 * @exception	Throws an Exception while processing a database query.
	 *
	 */
	private function _LoadTemplates()
	{
		$templates		= array();
		$templateNames	= array();
		try
		{
			//	Gets the list of template names based on the status code.
			if ($this->statusCode == 200)
				$templateNames		= $this->GetObjectNames_("template");
			else
				$templateNames[]	= array("template" => "ContentView", "actionStep" => "view");

			//	Gets the list of templates.
			if (isset($templateNames) && count($templateNames) > 0)
			{
				foreach ($templateNames as $templateName)
					$templates[] = $templateName;
			}
			else
				throw new Exception("Template not found");
		}
		catch (Exception $ex) { throw $ex; }
		return $templates;
	}

	/**
	 * Gets the list of object names to be loaded.
	 *
	 * @access	protected
	 * @param	string	$type	Name of object to be loaded.
	 * @return	array			Returns the list of object names to be loaded.
	 * @exception				Throws an Exception while processing a database query.
	 *
	 */
	protected function GetObjectNames_($type)
	{
		$names	= array();
		$db		= null;
		$qry	= null;
		try
		{
			$db = new Database("MySQL");
			$qry = "CALL cms_Get".ucwords(strtolower($type))."Names(";
			$qry .= $this->moduleID.", ";
			$qry .= $this->request->pageID.", ";
			$qry .= "'module'";
			$qry .= ")";
			//Debug::PrintScreen("h1", $qry);
			$db->Query($qry);
			while ($name = $db->Fetch())
				$names[] = $name;
		}
		catch (Exeption $ex) { throw $ex; }
		return $names;
	}

	/**
	 * Replaces the tags in the template
	 *
	 * @access	protected
	 * @param	array	$controls	Set of controls to be used in the template.
	 *
	 */
	protected function ReplaceTemplateTags_(&$contents, $controls)
	{
		$pattern		= null;
		$replacement	= null;
		foreach ($controls as $control => $properties)
		{
			if ($properties["type"] == "array")	//	Renders controls if the control is a set of sub controls.
			{
				//	Sets the contents between the opening and ending tag pair.
				$pattern = "/{\/?\s*".TEMPLATE_TAG_PREFIX.":\s*".$control."\s*(\/\/)?}/";
				if (preg_match_all($pattern, $contents, $matches, PREG_SET_ORDER) == 3)
				{
					//	Gets the template unit inside the opening and ending tag pair.
					$innerHTML		= null;
					//echo count($properties["value"]);
					if (!empty($properties["value"]) && count($properties["value"]) > 0)
					{
						//	Gets the template for iteration.
						$innerTemplate	= $this->_GetInnerTemplate($contents, $matches[0][0], $matches[1][0]);

						//	Iterates the template as many times as the number of array values.
						foreach ($properties["value"] as $property)
						{
							if (!empty($property) && count($property) > 0)
							{
								//	Removes the opening and ending tag pair.
								$pattern = "/{\/?\s*".TEMPLATE_TAG_PREFIX.":\s*".$control."\.".substr($control, 0, strlen($control)-1)."\s*}/";
								if (preg_match_all($pattern, $innerTemplate, $matches, PREG_SET_ORDER) == 2)
									$innerTemplate = str_replace($matches[1][0], "", str_replace($matches[0][0], "", $innerTemplate));
							}

							//	Replaces the single tag pattern.
							foreach ($property as $subControl => $subValue)
							{
								foreach ($subValue as $key => $value)
								{
									$pattern		= "/\{\s*".TEMPLATE_TAG_PREFIX.":\s*".$control."\.".substr($control, 0, strlen($control)-1)."\.".$subControl."\.".$key."\s*\/\}/";
									$replacement	= $value;
									$innerTemplate	= preg_replace($pattern, $replacement, $innerTemplate);
								}
							}
							$innerHTML .= $innerTemplate."\n";
						}
						
						//	Replaces the whole innerTemplate with the innerHTML.
						$pattern = "/{\/?\s*".TEMPLATE_TAG_PREFIX.":\s*".$control."\s*(\/\/)?}/";
						preg_match_all($pattern, $contents, $matches, PREG_SET_ORDER);
						$innerTemplate = $this->_GetInnerTemplate($contents, $matches[0][0], $matches[2][0]);
						$contents = str_replace($matches[0][0].$innerTemplate.$matches[2][0], $innerHTML, $contents);
					}
					else
					{
						$innerTemplate	= $this->_GetInnerTemplate($contents, $matches[1][0], $matches[2][0]);
						$innerHTML .= $innerTemplate."\n";
					}
					//Debug::PrintScreen("pre", $contents);
				}
			}
			else	//	Renders control if the control is single itself.
			{
				$pattern = "/{\/?\s*".TEMPLATE_TAG_PREFIX.":\s*".$control."\s*}/";
				if (preg_match_all($pattern, $contents, $matches, PREG_SET_ORDER) == 2)
				{
					//	Removes the content corresponding to the tag pair, if relevant data does not exist.
					if (empty($properties["value"]))
					{
						$innerTemplate	= $this->_GetInnerTemplate($contents, $matches[0][0], $matches[1][0]);
						$contents		= str_replace($matches[0][0].$innerTemplate.$matches[1][0], "", $contents);
					}
					//	Removes the opening and ending tag pair.
					else
						$contents = str_replace($matches[1][0], "", str_replace($matches[0][0], "", $contents));
				}

				//	Replaces the single tag pattern.
				foreach ($properties as $key => $value)
				{
					$pattern		= "/\{\s*".TEMPLATE_TAG_PREFIX.":\s*".$control."\.".$key."\s*\/\}/";
					$replacement	= $value;
					$contents		= preg_replace($pattern, $replacement, $contents);
				}
				//Debug::PrintScreen("pre", $contents);
			}
			//Debug::PrintScreen("pre", $contents);
		}
	}
	
	private function _GetInnerTemplate($contents, $start, $end)
	{
		$start			= strpos($contents, $start) + strlen($start);
		$length			= strpos($contents, $end) - $start;
		$innerTemplate	= substr($contents, $start, $length);
		return $innerTemplate;
	}
}
?>
